/*
 * Copyright (C) 2015 Tomás Ruiz-López.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sgb.capital.view.widget.xrecyclerview;

import android.content.Context;
import android.util.SparseBooleanArray;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

import androidx.recyclerview.widget.RecyclerView;

/**
 * 继承该adapter,实现二级列表
 * An extension to RecyclerView.Adapter to provide sections with headers and footers to a
 * RecyclerView. Each section can have an arbitrary number of items.
 *
 * @param <H>  Class extending RecyclerView.ViewHolder to hold and bind the header view
 * @param <VH> Class extending RecyclerView.ViewHolder to hold and bind the items view
 * @param <F>  Class extending RecyclerView.ViewHolder to hold and bind the footer view
 */
public abstract class ZSectionedRecyclerViewAdapter<T, D, H extends RecyclerView.ViewHolder,
        VH extends RecyclerView.ViewHolder,
        F extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    protected static final int TYPE_SECTION_HEADER = -1;
    protected static final int TYPE_SECTION_FOOTER = -2;
    protected static final int TYPE_ITEM = -3;

    private int[] sectionForPosition = null;
    private int[] positionWithinSection = null;
    private boolean[] isHeader = null;
    private boolean[] isFooter = null;
    private int count = 0;

    protected Context mContext;
    protected List datas;
    protected int headerLayoutId;
    protected int descLayoutId;

    private SparseBooleanArray mBooleanMap;//记录下哪个section是被打开的

    /**
     * 是否添设置item选中状态
     */
    protected boolean isItemSelect = false;
    /**
     * 是否添设置item多选
     */
    protected boolean multiSelect = false;
    /**
     * 是否添设置item选中状态
     */
    private boolean state = true;
    /**
     * 默认选中位置
     */
    private int defItem = -1;
    private SparseBooleanArray checkList = new SparseBooleanArray();
    private List<D> checkDatas = new ArrayList<>();

    public ZSectionedRecyclerViewAdapter() {
        super();
        registerAdapterDataObserver(new SectionDataObserver());
    }

    public ZSectionedRecyclerViewAdapter(Context context, int headerLayoutId, int descLayoutId, List<T> datas) {
        super();
        this.mContext = context;
        this.headerLayoutId = headerLayoutId;
        this.descLayoutId = descLayoutId;
        mBooleanMap = new SparseBooleanArray();
        this.datas = datas;
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
        sectionOpend();
        registerAdapterDataObserver(new SectionDataObserver());
    }

    public void setData(List datas) {
        this.datas = datas;
        sectionOpend();
        notifyDataSetChanged();
    }

    public void addDatas(List newDatas) {
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
        int last = datas.size();
        this.datas.addAll(newDatas);
        //      notifyItemInserted(last + 1);
        notifyDataSetChanged();
    }

    //默认展开列表
    private void sectionOpend() {
        if (this.datas == null) {
            this.datas = new ArrayList<>();
        }
        for (int i = 0; i < datas.size(); i++) {
            mBooleanMap.put(i, true);
        }
    }

    //收起展开列表
    protected void sectionSwitch(int section) {
        boolean isOpen = mBooleanMap.get(section);
        mBooleanMap.put(section, !isOpen);
        notifyDataSetChanged();
    }

    protected boolean isOpen(int section) {
        return mBooleanMap.get(section);
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        setupIndices();
    }

    /**
     * Returns the sum of number of items for each section plus headers and footers if they
     * are provided.
     */
    @Override
    public int getItemCount() {
        return count;
    }

    private void setupIndices() {
        count = countItems();
        allocateAuxiliaryArrays(count);
        precomputeIndices();
    }

    private int countItems() {
        int count = 0;
        int sections = getSectionCount();

        for (int i = 0; i < sections; i++) {
            count += 1 + getItemCountForSection(i) + (hasFooterInSection(i) ? 1 : 0);
        }
        return count;
    }

    private void precomputeIndices() {
        int sections = getSectionCount();
        int index = 0;

        for (int i = 0; i < sections; i++) {
            setPrecomputedItem(index, true, false, i, 0);
            index++;

            for (int j = 0; j < getItemCountForSection(i); j++) {
                setPrecomputedItem(index, false, false, i, j);
                index++;
            }

            if (hasFooterInSection(i)) {
                setPrecomputedItem(index, false, true, i, 0);
                index++;
            }
        }
    }

    private void allocateAuxiliaryArrays(int count) {
        sectionForPosition = new int[count];
        positionWithinSection = new int[count];
        isHeader = new boolean[count];
        isFooter = new boolean[count];
    }

    private void setPrecomputedItem(int index, boolean isHeader, boolean isFooter, int section, int position) {
        this.isHeader[index] = isHeader;
        this.isFooter[index] = isFooter;
        sectionForPosition[index] = section;
        positionWithinSection[index] = position;
    }

    /**
     * 一共有多少个section需要展示， 返回值是我们最外称list的大小，在我们的示例图中，
     * 对应的为热门品牌—商业区—热门景点 等，对应的数据是我们的allTagList
     *
     * @Override
     */
    private int getSectionCount() {
        return ZDatalUtils.isEmpty(datas) ? 0 : datas.size();
    }

    /**
     * 来展示content内容区域，返回值是我们需要展示多少内容，在本例中，我们超过8条数据只展示8条，
     * 点击展开后就会展示全部数据，逻辑就在这里控制。 对应数据结构为tagInfoList
     *
     * @param section
     * @return
     */
    private int getItemCountForSection(int section) {
        boolean empty = ZDatalUtils.isEmpty(((ZSecondaryEntity) datas.get(section)).getDatas());
        if (empty) {
            return 0;
        }
        int count = ((ZSecondaryEntity) datas.get(section)).getDatas().size();
        if (count >= 1 && !mBooleanMap.get(section)) {
            count = 0;
        }
        if (section == 0 && mBooleanMap.get(section)) {
            count = ((ZSecondaryEntity) datas.get(section)).getDatas().size();
        }
        return count;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder;

        if (isSectionHeaderViewType(viewType)) {
            viewHolder = ZHeaderHolder.get(mContext, parent, headerLayoutId);
        } else if (isSectionFooterViewType(viewType)) {
            viewHolder = ZHeaderHolder.get(mContext, parent, headerLayoutId);
        } else {
            viewHolder = ZDescHolder.get(mContext, parent, descLayoutId);
        }

        return viewHolder;
    }

    public void setState(boolean state) {
        if (!state) {
            checkList.clear();
        }
        notifyDataSetChanged();
    }

    public void setDefItem(int defItem) {
        this.defItem = defItem;
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
        final int section = sectionForPosition[position];
        final int index = positionWithinSection[position];

        if (isSectionHeaderPosition(position)) {
            onBindSectionHeaderViewHolder((H) holder, section, (T) datas.get(section));
        } else if (isSectionFooterPosition(position)) {
            onBindSectionFooterViewHolder((F) holder, section);
        } else {
            holder.itemView.setSelected(false);
            if (checkList.size() > 0) {
                if (checkList.get(position)) {
                    holder.itemView.setSelected(true);
                } else {
                    holder.itemView.setSelected(false);
                }
            }
            if (defItem != -1) {
                if (position == (defItem + 1)) {
                    holder.itemView.setSelected(true);
                }
            }
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    defItem = -1;
                    if (isItemSelect) {
                        checkList.clear();
                        int desc = 0;
                        if (section > 0) {
                            for (int i = 0; i < section; i++) {
                                desc = desc + ((ZSecondaryEntity) datas.get(i)).getDatas().size();
                            }
                        }
                        checkList.put((section + 1) + (desc + index), true);
                        if (onItemClickListener != null) {
                            List<D> dList = ((ZSecondaryEntity) datas.get(section)).getDatas();
                            D s = dList.get(index);
                            onItemClickListener.onItemClick(s, section, index);
                        }
                        notifyDataSetChanged();
                    } else if (multiSelect) {
                        if (!holder.itemView.isSelected()) {
                            int desc = 0;
                            if (section > 0) {
                                for (int i = 0; i < section; i++) {
                                    desc = desc + ((ZSecondaryEntity) datas.get(i)).getDatas().size();
                                }
                            }
                            checkList.put((section + 1) + (desc + index), true);
                            List<D> dList = ((ZSecondaryEntity) datas.get(section)).getDatas();
                            D s = dList.get(index);
                            checkDatas.add(s);
                        } else {
                            int desc = 0;
                            if (section > 0) {
                                for (int i = 0; i < section; i++) {
                                    desc = desc + ((ZSecondaryEntity) datas.get(i)).getDatas().size();
                                }
                            }
                            checkList.put((section + 1) + (desc + index), false);
                            List<D> dList = ((ZSecondaryEntity) datas.get(section)).getDatas();
                            D s = dList.get(index);
                            checkDatas.remove(s);
                        }
                        if (onItemMultiClick != null) {
                            onItemMultiClick.onItemMultiClick(checkDatas, section, index);
                        }
                        notifyDataSetChanged();
                    } else {
                        if (onItemClickListener != null) {
                            List<D> dList = ((ZSecondaryEntity) datas.get(section)).getDatas();
                            D s = dList.get(index);
                            onItemClickListener.onItemClick(s, section, index);
                        }
                    }
                }
            });

            onBindItemViewHolder((VH) holder, section, index, (D) ((ZSecondaryEntity) datas.get(section)).getDatas().get(index));
        }

    }

    @Override
    public int getItemViewType(int position) {

        if (sectionForPosition == null) {
            setupIndices();
        }

        int section = sectionForPosition[position];
        int index = positionWithinSection[position];

        if (isSectionHeaderPosition(position)) {
            return getSectionHeaderViewType(section);
        } else if (isSectionFooterPosition(position)) {
            return getSectionFooterViewType(section);
        } else {
            return getSectionItemViewType(section, index);
        }

    }

    protected int getSectionHeaderViewType(int section) {
        return TYPE_SECTION_HEADER;
    }

    protected int getSectionFooterViewType(int section) {
        return TYPE_SECTION_FOOTER;
    }

    protected int getSectionItemViewType(int section, int position) {
        return TYPE_ITEM;
    }

    /**
     * Returns true if the argument position corresponds to a header
     */
    public boolean isSectionHeaderPosition(int position) {
        if (isHeader == null) {
            setupIndices();
        }
        return isHeader[position];
    }

    /**
     * Returns true if the argument position corresponds to a footer
     */
    public boolean isSectionFooterPosition(int position) {
        if (isFooter == null) {
            setupIndices();
        }
        return isFooter[position];
    }

    protected boolean isSectionHeaderViewType(int viewType) {
        return viewType == TYPE_SECTION_HEADER;
    }

    protected boolean isSectionFooterViewType(int viewType) {
        return viewType == TYPE_SECTION_FOOTER;
    }

    /**
     * 判断是否需要底部footer布局，在该例中，我们并不需要显示footer，所以默认返回false就可以，
     * 如果你对应的section需要展示footer布局，那么就在对应的section返回true就行了
     *
     * @param section
     * @return
     */
    private boolean hasFooterInSection(int section) {
        return false;
    }

    public void resetCheckDatas() {
        this.checkDatas.clear();
        this.checkList.clear();
        notifyDataSetChanged();
    }

    /**
     * Binds data to the header view of a given section
     */
    protected abstract void onBindSectionHeaderViewHolder(H holder, int section, T t);

    /**
     * Binds data to the footer view of a given section
     */
    protected abstract void onBindSectionFooterViewHolder(F holder, int section);

    /**
     * Binds data to the item view for a given position within a section
     */
    protected abstract void onBindItemViewHolder(VH holder, int section, int position, D d);

    class SectionDataObserver extends RecyclerView.AdapterDataObserver {
        @Override
        public void onChanged() {
            setupIndices();
        }
    }

    public int getItemPosition(int position) {
        return positionWithinSection[position];
    }


    public void setItemSelect(boolean itemSelect) {
        isItemSelect = itemSelect;
    }

    public void setMultiSelect(boolean multiSelect) {
        this.multiSelect = multiSelect;
    }

    protected OnItemClick onItemClickListener;

    public void setOnItemClickListener(ZSectionAdapterOnItemClick<D> onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    public interface OnItemClick<D> {
        void onItemClick(D d, int section, int position);
    }

    protected OnItemMultiClick onItemMultiClick;

    public void setOnItemMultiClick(OnItemMultiClick<D> onItemMultiClick) {
        this.onItemMultiClick = onItemMultiClick;
    }

    public interface OnItemMultiClick<D> {
        void onItemMultiClick(List<D> tList, int section, int position);
    }
}
